using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Phoenix.ActionResults;
using Phoenix.Filters;
using Phoenix.Utilities;

namespace Phoenix.Framework
{
    public abstract class ActionDescriptorBase : IActionDescriptor
    {
        readonly MethodDescriptor methodDescriptor;

        protected ActionDescriptorBase(MethodDescriptor methodDescriptor, IControllerDescriptor controllerDescriptor)
        {
            this.methodDescriptor = methodDescriptor;
            ControllerDescriptor = controllerDescriptor;
        }

        protected T Invoke<T>(IController controller, ControllerActionContext controllerActionContext)
        {
            object[] parameters;

            if (methodDescriptor.HasQueryStringArgument)
            {
                parameters = new object[] { controllerActionContext.ControllerAction.QueryStringArguments }
                    .Concat(controllerActionContext.Parameters.Select(p => p.Value))
                    .ToArray();
            }
            else
            {
                parameters = controllerActionContext.Parameters.Select(p => p.Value).ToArray();
            }

            return (T)DelegateInvoker
                          .CreateInvoker(controller, methodDescriptor.MethodInfo)
                          .Call(parameters);
        }

        public abstract Task<ActionResult> Execute(IController controller, ControllerActionContext controllerActionContext);

        public IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache)
        {
            return ReflectedAttributeCache.GetMethodFilterAttributes(methodDescriptor.MethodInfo);
        }

        public IControllerDescriptor ControllerDescriptor { get; private set; }
    }
}